package com.sig.common.event;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 事件派发器的默认实现
 *
 * @author sig
 * @since 2019/2/21
 */
public class EventDispatcher<T extends GeneralEvent> implements IDispatcher<T> {
    protected Map<Class<? extends T>, List<GeneralEventListener<T>>> classListeners = new ConcurrentHashMap<>();

    @Override
    public void addEventListener(Class<? extends T> eventType, GeneralEventListener<T> listener) {
        if (eventType == null || listener == null)
            return;
        List<GeneralEventListener<T>> listeners = classListeners.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>());
        if (!listeners.contains(listener)) {
            synchronized (listeners) {
                // int index = listeners.indexOf(listener);
                // 考虑性能用二分查找法
                int index = Collections.binarySearch(listeners, listener, null);
                if (index < 0) {
                    listeners.add(-(index + 1), listener);
                } else {
                    listeners.add(index, listener);
                }
            }
        }
    }

    @Override
    public boolean removeEventListener(Class<? extends T> eventType, GeneralEventListener<T> listener) {
        if (eventType == null || listener == null)
            return false;
        if (classListeners == null)
            return false;
        List<GeneralEventListener<T>> listeners = classListeners.get(eventType);
        if (listeners == null)
            return false;
        return listeners.remove(listener);
    }

    @Override
    public void reset() {
        if (MapUtils.isNotEmpty(classListeners))
            classListeners.clear();
    }

    @Override
    public boolean hasEventListener(Class<? extends T> eventType) {
        if (eventType == null)
            return false;
        if (classListeners == null)
            return false;
        List<GeneralEventListener<T>> listeners = classListeners.get(eventType);
        return CollectionUtils.isNotEmpty(listeners);
    }

    @Override
    public boolean hasEventListener(Class<? extends T> eventType, GeneralEventListener<T> listener) {
        if (eventType == null)
            return false;
        if (classListeners == null)
            return false;
        List<GeneralEventListener<T>> listeners = classListeners.get(eventType);
        if (listeners == null)
            return false;
        return listeners.contains(listener);
    }

    @Override
    public boolean hasEventListener(Class<? extends T> eventType, Class<? extends GeneralEventListener<T>> listener) {
        if (eventType == null)
            return false;
        if (classListeners == null)
            return false;
        List<GeneralEventListener<T>> listeners = classListeners.get(eventType);
        if (listeners == null)
            return false;
        for (GeneralEventListener<T> eventListener : listeners) {
            if (listener.isAssignableFrom(eventListener.getClass()))
                return true;
        }
        return false;
    }

    @Override
    public boolean dispatchEvent(T event) {
        if (classListeners == null)
            return false;
        List<GeneralEventListener<T>> listeners = classListeners.get(event.getClass());
        if (listeners == null)
            return false;
        for (GeneralEventListener<T> listener : listeners) {
            listener.onEvent(event);
        }
        return false;
    }
}
